package com.tjstudy.tcpcs;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.util.Iterator;


public class TCPServer {
	private static Selector serverSelector;
	private static ByteBuffer serBuffer;

	public static void main(String[] args) throws IOException {
		//get listen port
		if(args.length < 1){
			System.out.println("需要指定服务端口");
			return;
		}
		int port = Integer.valueOf(args[0]);
		
		//新建NIO 通道 & 设置为非阻塞
		ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
		serverSocketChannel.configureBlocking(false);
		
		//创建基于NIO通道的socket & 绑定到指定端口
		serverSocketChannel.socket().bind(new InetSocketAddress(port));
		
		//注册选择器到NIO通道
		serverSelector = Selector.open();
		serverSocketChannel.register(serverSelector, SelectionKey.OP_ACCEPT);
		
		serBuffer = ByteBuffer.allocate(1024);

		TCPServer server = new TCPServer();
		new Thread(server.new ServerThread()).start();
	}

	private static byte[] short2Byte(int s) {
		byte[] shortBuf = new byte[2];
		for (int i = 0; i < 2; i++) {
			int offset = (shortBuf.length - 1 - i) * 8;
			shortBuf[1 - i] = (byte) ((s >>> offset) & 0xff);
		}
		return shortBuf;
	}
	
	class ServerThread implements Runnable
	{
		private String receivedMsg;
		
		@Override
		public void run() 
		{
			while (true) 
			{
				try {
					int select = serverSelector.select();
					if (select == 0) {
						// System.out.println("select:" + select);
						continue;
					}
				} catch (IOException e) {
					e.printStackTrace();
				}
				
				Iterator<SelectionKey> sKeys = serverSelector.selectedKeys().iterator();
				while (sKeys.hasNext()) {
					SelectionKey key = sKeys.next();
					
					if (key.isAcceptable()) {
						System.out.println("【system】有新客户端请求，建立与该客户端的新连接...");
						ServerSocketChannel serverChannel = (ServerSocketChannel) key.channel();
						try {
							SocketChannel clientChannel = serverChannel.accept();
							clientChannel.configureBlocking(false);
							clientChannel.register(serverSelector,SelectionKey.OP_READ);
						} catch (IOException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
					} else if (key.isReadable()) {
						String s = "";
						serBuffer.clear();
						System.out.println("【system】收到客户端发送的数据，准备读取...");
						SocketChannel clientChannel = (SocketChannel) key.channel();
						
						try {
							int read = clientChannel.read(serBuffer);
							if (read == -1) {
								//System.out.println("【没有数据可读】");
								continue;
							}
							serBuffer.flip();
							s = new String(serBuffer.array(), 0, serBuffer.limit(),"GBK");
							receivedMsg = s;
							
							//for test
							System.out.println("\t Received : "+receivedMsg);
							//end
							
							clientChannel.configureBlocking(false);
							clientChannel.register(serverSelector,SelectionKey.OP_WRITE);
						} catch (IOException e) {
							e.printStackTrace();
							try {
								clientChannel.close();
								key.cancel();
							} catch (IOException e1) {
								e1.printStackTrace();
							}
						}
					} else if (key.isWritable() && key.isValid()) {
						System.out.println("【system】给客户端回送数据，准备发送...");
						SocketChannel clientChannel = (SocketChannel) key.channel();
						
						serBuffer.clear();
						String echo = "echo : " + receivedMsg + "\r\n";
						serBuffer.put(echo.getBytes(Charset.forName("GBK")));
						serBuffer.flip();
						
						//for test
						String fortest = new String(serBuffer.array(),0,serBuffer.limit(),Charset.forName("GBK"));
						System.out.println("\t Sended : "+fortest);
						//end
						
						try {
							clientChannel.write(serBuffer);
							clientChannel.configureBlocking(false);
							clientChannel.register(serverSelector,SelectionKey.OP_READ);
						} catch (IOException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
							try {
								clientChannel.close();
								key.cancel();
							} catch (IOException e1) {
								e1.printStackTrace();
							}
						}
					}
					sKeys.remove();  //必须remove，否则会死循环
				}
			}
		}
	}
}


